//角色属性相关
package attr

import (
	"encoding/json"
	"fmt"
	com_attr "sanguo/node/common/attr"
	cs_message "sanguo/protocol/cs/message"

	"github.com/golang/protobuf/proto"
)

type AttrEventReceiver interface {
	OnAttrDirty()
}

var (
	ErrInvaildAttr = fmt.Errorf("invaild attr")
)

type AttrPair struct {
	Idx int32
	Val int64
}

type RoleAttr struct {
	attrList  map[int32]*AttrPair
	attrDirty map[int32]bool
	dbDirty   bool
	receiver  AttrEventReceiver
}

//验证表数据
func (this *RoleAttr) CheckAttr() {
	//判断属性条数是否需要增加
	for i := int32(0); i < com_attr.AttrMax; i++ {
		if this.attrList[i] == nil {
			attr := &AttrPair{
				Idx: int32(i),
				Val: int64(0),
			}
			this.attrList[attr.Idx] = attr
		}
	}

}

func (this *RoleAttr) GetAttr(idx int32) (int64, error) {
	if idx >= 0 && idx < int32(len(this.attrList)) {
		return this.attrList[idx].Val, nil
	} else {
		return 0, ErrInvaildAttr
	}
}

func (this *RoleAttr) SetAttr(idx int32, val int64) error {
	if idx >= 0 && idx < int32(len(this.attrList)) {
		ele := this.attrList[idx]
		if ele.Val == val {
			return nil
		}

		ele.Val = val
		this.attrDirty[idx] = true
		this.dbDirty = true
		this.receiver.OnAttrDirty()

		return nil
	} else {
		return ErrInvaildAttr
	}
}

func (this *RoleAttr) AddAttr(idx int32, val, min, max int64) (int64, error) {

	if idx >= 0 && idx < int32(len(this.attrList)) {

		ele := this.attrList[idx]

		oldVal := ele.Val
		newVal := ele.Val + val

		if newVal < min {
			newVal = min
		}

		if newVal > max {
			newVal = max
		}
		if oldVal == newVal {
			return newVal, nil
		}

		ele.Val = newVal
		this.attrDirty[idx] = true
		this.dbDirty = true
		this.receiver.OnAttrDirty()

		return newVal, nil
	} else {
		return 0, ErrInvaildAttr
	}
}

//打包所有属性，不改变dirty标记
func (this *RoleAttr) PackAllAttr() []*cs_message.Attr {
	ret := []*cs_message.Attr{}
	for _, v := range this.attrList {
		attr := &cs_message.Attr{
			Id:  proto.Int32(v.Idx),
			Val: proto.Int64(v.Val),
		}
		ret = append(ret, attr)
	}
	return ret
}

//打包dirty属性并清除dirty标记
func (this *RoleAttr) PackAttrModify() []*cs_message.Attr {
	ret := []*cs_message.Attr{}
	for i, v := range this.attrDirty {
		if v {
			delete(this.attrDirty, i)

			attr := &cs_message.Attr{
				Id:  proto.Int32(this.attrList[int32(i)].Idx),
				Val: proto.Int64(this.attrList[int32(i)].Val),
			}
			ret = append(ret, attr)
		}
	}
	return ret
}

func (this *RoleAttr) PackJson(fields map[string]interface{}) {
	if this.dbDirty {
		jsonStr, err := json.Marshal(this.attrList)
		if nil == err {
			this.dbDirty = true
			fields["attr"] = jsonStr
		}
	}
}

func (this *RoleAttr) IsDirty() bool {
	return this.dbDirty

}

func (this *RoleAttr) SetDirtyFlag() {
	this.dbDirty = true
}

func (this *RoleAttr) ClearDirtyFlag() {
	this.dbDirty = false
}

func (this *RoleAttr) Init(receiver AttrEventReceiver, attrs map[int32]*AttrPair) {
	this.attrList = attrs
	this.attrDirty = map[int32]bool{}
	this.dbDirty = false
	this.receiver = receiver

}
